/*
 * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jef.tools.string;

import jef.tools.ArrayUtils;

public class StringSpliter {
	/**
	 * 这个对象是为了在复杂的字符串分割过程中，避免在内存中产生过多的String对象,实现节约资源提供性能的目的,
	 * 尤其是在对较长的String对象操作时，效率要高出很多。
	 * 实现原理是使用了Substring类，由于Substring类只通过简单的int型数字记录分割点的位置，不实际分割字串对象，所以节省系统资源
	 * 
	 * Chart of a String cutter 
	 * -----------============------------------
	 * |           |         |                 |
	 * begin          keyStr                 end
	 * 
	 */
	private Substring keyword;
	private Substring source;
	public static final int MODE_FROM_LEFT = 0;// 从左向右查找
	public static final int MODE_FROM_RIGHT = 1;// 从右向左查找
	private int findMode = MODE_FROM_LEFT;

	public StringSpliter(Substring source) {
		this.source = source;
		this.keyword = null;
	}

//	public StringSpliter(Substring source, int begin, int end) {
//		this.source = source;
//		this.keyword = source.sub(begin, end);
//	}

	public StringSpliter(String source){
		this.source = new Substring(source);
		this.keyword = null;
	}
	
	public Substring getKeyword() {
		return keyword;
	}

	public Substring getSource() {
		return source;
	}

	public void setSource(Substring source) {
		this.source = source;
		this.keyword=null;
	}
	
	/**
	 * 将key向两边扩展，如果两边的相邻字符和指定的字符相同的话，将其扩展到key的范围
	 * @param chars
	 */
	public boolean expandKey(char[] chars){
		boolean res=expandKeyLeft(chars);
		if(expandKeyRight(chars)){
			res=true;
		}
		return res;
	}

	/**
	 * 如果左侧字符在指定列表中，则向左扩展key
	 * @param chars
	 * @return
	 */
	public boolean expandKeyLeft(char[] chars){
		boolean res=false;
		if(keyword==null)return res;
		Substring left=getLeft();
		while(left.lastCharacter()!=null && ArrayUtils.contains(chars,left.lastCharacter().charValue())){
			left.setEnd(left.getEnd()-1);
			res=true;
		}
		if(res)this.keyword=source.subAbsoultOffset(left.getEnd(), keyword.getEnd());
		return res;
	}

	/**
	 * 如果右侧字符在指定的列表中，则向右扩展key
	 * @param chars
	 * @return
	 */
	public boolean expandKeyRight(char[] chars){
		boolean res=false;
		if(keyword==null)return res;
		Substring right=getRight();
		while(right.firstCharacter()!=null && ArrayUtils.contains(chars,right.firstCharacter().charValue())){
			right.setStart(right.getStart()+1);
			res=true;
		}
		if(res)this.keyword=source.subAbsoultOffset(keyword.getStart(), right.getStart());
		return res;
	}
	
	public boolean expandKeyLeft(int count){
		if(source.getStart()>keyword.getStart()-count){//如果key越过souce边界，则返回
			return false;			
		}
		if(keyword.getEnd()<keyword.getStart()-count){//如果key越过key end边界，则返回
			return false;			
		}
		keyword.setStart(keyword.getStart()-count);
		return true;
		
	}
	
	public boolean expandKeyRight(int count){
		if(source.getEnd()<keyword.getEnd()+count){
			return false;	
		}
		if(keyword.getStart()>keyword.getEnd()+count){
			return false;	
		}
		keyword.setEnd(keyword.getEnd()+count);
		return true;
	}
	
	/**
	 * 向两端扩张key的范围，直到出现指定的字符才停下（指定字符不含）
	 * @param chars
	 * @return
	 */
	public boolean expandKeyUntil(char[] chars){
		boolean res=expandKeyLeftUntil(chars);
		if(expandKeyRightUntil(chars)){
			res=true;
		}
		return res;
	}
	
	/**
	 * 向左扩张Key的范围，直到出现指定的字符才停下（指定字符不含）
	 * @param chars
	 * @return
	 */
	public boolean expandKeyLeftUntil(char[] chars){
		boolean res=false;
		if(keyword==null)return res;
		Substring left=getLeft();
		while(left.lastCharacter()!=null && !ArrayUtils.contains(chars,left.lastCharacter().charValue())){
			left.setEnd(left.getEnd()-1);
			res=true;
		}
		if(res)this.keyword=source.subAbsoultOffset(left.getEnd(), keyword.getEnd());
		return res;
	}
	
	/**
	 * 向右扩张Key的范围，直到出现指定的字符才停下（指定字符不含）
	 * @param chars
	 * @return
	 */
	public boolean expandKeyRightUntil(char[] chars){
		boolean res=false;
		if(keyword==null)return res;
		Substring right=getRight();
		while(right.firstCharacter()!=null && !ArrayUtils.contains(chars,right.firstCharacter().charValue())){
			right.setStart(right.getStart()+1);
			res=true;
		}
		if(res)this.keyword=source.subAbsoultOffset(keyword.getStart(), right.getStart());
		return res;
	}
	/**
	 * 获取左边部分
	 * @return
	 */
	public Substring getLeft() {
		if (keyword == null) {
			if (findMode == MODE_FROM_LEFT) {
				return source;
			} else {
				return null;
			}
		} else {
			return source.subAbsoultOffset(source.getStart(), keyword.getStart());
		}
	}

	/**
	 * 获取右边部分
	 * 
	 * @return
	 */
	public Substring getRight() {
		if (keyword == null) {
			if (findMode == MODE_FROM_LEFT) {
				return null;
			} else {
				return source;
			}
		} else {
			return source.subAbsoultOffset(keyword.getEnd(), source.getEnd());
		}
	}

	/**
	 * 得到带key的左边部分
	 */
	public Substring getLeftWithKey() {
		if (keyword == null) {
			if (findMode == MODE_FROM_LEFT) {
				return null;
			} else {
				return source;
			}
		} else {
			return source.subAbsoultOffset(source.getStart(), keyword.getEnd());
		}
	}

	/**
	 * 得到带key的右边部分
	 */
	public Substring getRightWithKey() {
		if (keyword == null) {
			if (findMode == MODE_FROM_LEFT) {
				return null;
			} else {
				return source;
			}
		} else {
			return source.subAbsoultOffset(keyword.getStart(), source.getEnd());
		}
	}

	/**
	 * 设置一个值，查找，如果找到就形成keyStr对象，从而将对象可拆分为三个Substring.
	 * @param str
	 */
	public boolean setKey(String str) {
		if(str==null){
			this.keyword = null;
			return false;
		}
		int n=-1;
		if (findMode == MODE_FROM_RIGHT) {
			n= source.lastIndexOf(str);
		} else {
			n= source.indexOf(str);
		}
		if(n>-1){
			this.keyword = source.sub(n, n+str.length());
			return true;
		}else{
			this.keyword = null;
			return false;
		}
	}
	
	public boolean setKey(int ketStart,int keyEnd) {
		try{
			this.keyword=source.sub(ketStart, keyEnd);
			return true;
		}catch (IllegalArgumentException e){
			return false;
		}
	}
	
	public boolean setKey(char str) {
		if(str==0){
			this.keyword = null;
			return false;
		}
		int n=-1;
		if (findMode == MODE_FROM_RIGHT) {
			n= source.lastIndexOf(str);
		} else {
			n= source.indexOf(str);
		}
		if(n>-1){
			this.keyword = source.sub(n, n+1);
			return true;
		}else{
			this.keyword = null;
			return false;
		}
	}
//目前算法效率不够高，还可以继续优化
	public boolean setKeyOfAny(String[] ss) {
		int find=-1;
		int length=0;
		for(String str:ss){
			if (findMode == MODE_FROM_RIGHT) {
				int n= source.lastIndexOf(str);
				if(n>find || find==-1){
					find=n;
					length=str.length();
				}
			} else {
				int n= source.indexOf(str);
				if(n>-1 && (n<find || find==-1)){
					find=n;
					length=str.length();
				}
			}
		}
		if(find>-1){
			this.keyword = source.sub(find, find+length);
		}else{
			this.keyword = null;
		}
		return keyword!=null;
	}

	public boolean setKeyOfAny(char[] chars) {
		int find=-1;
		for(char c:chars){
			if (findMode == MODE_FROM_RIGHT) {
				int n= source.lastIndexOf(c);
				if(n>find || find==-1){
					find=n;
				}
			} else {
				int n= source.indexOf(c);
				if(n>-1 && (n<find || find==-1)){
					find=n;
				}
			}
		}
		if(find>-1){
			this.keyword = source.sub(find, find+1);
		}else{
			this.keyword = null;
		}
		return keyword!=null;
	}

	public int getMode() {
		return findMode;
	}

	public void setMode(int mode) {
		this.findMode = mode;
	}
}
